<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');

class JR_Loader extends CI_Loader
{	
	public $work_space = "controller";

	public function current_user($user = 'get') 
	{
		$ci = CI_Controller::get_instance() ;
		return $ci->current_user($user);
	}

	function plugin($name,$class_name=null)
	{
		if ( ! class_exists('JR_Plugin'))
		{
			require_once(APPPATH.'core/JR_Plugin'.EXT);
		}
		
		$ci =  & get_instance();
		$class_name==null && $class_name = $name."_plugin";
		if(!isset($ci->$class_name))
		{
			require_once(APPPATH."plugins/$name/".$name."_plugin".EXT);
			$plugin_name = $name."_plugin";
			$ci->$class_name = new $plugin_name();
		}
	}
	
	function module($module, $vars = array(), $return = FALSE)
	{ 
		if ($module == '')
		{
			return;
		}
		
		$module = trim($module, '/');
		
		$CI =& get_instance();
		
		$default_controller = $CI->router->default_controller;
		
		if (strpos($module, '/') === FALSE)
		{
			$path = '';
			$controller = $default_controller;
			$method = 'index';
			$segments = array();
		}
		else
		{
			$segments = explode('/', $module);
		 	// print_r($segments);exit; 
			if (file_exists(APPPATH.'modules/'.$segments[0].'/controllers/'.CONTROL_FOLDER.'/'.$segments[1].EXT))
			{
				$path = '';
				$module = $segments[0];
				$controller = $segments[1];
				$method = isset($segments[2]) ? $segments[2] : 'index';
			}
			/*
			// 子目录下有模块？
			elseif (is_dir(APPPATH.'modules/'.$segments[0].'/'.$segments[1].'/controllers'))
			{
				// Set the directory and remove it from the segment array
				$path = $segments[0];
				$segments = array_slice($segments, 1);
		
				if (count($segments) > 0)
				{
					// 子目录下有模块？
					if (is_dir(APPPATH.'modules/'.$path.'/'.$segments[0].'/controllers'))
					{
						$module = $segments[0];
						$controller = isset($segments[1]) ? $segments[1] : $default_controller;
						$method = isset($segments[2]) ? $segments[2] : 'index';
					}
				}
				else
				{
					show_error('Unable to locate the module you have specified: '.$path);
				}
			}
			*/
			else
			{
				show_error('Unable to locate the module you have specified: '.$module);
			}
		
			if ($path != '') 
			{
				$path = rtrim($path, '/') . '/';
			}
		}
		
		$controller = str_replace(CONTROL_FOLDER."/","",$controller);
		// echo $controller;exit ; 
		// 模块名全部小写
		$module = strtolower($module);
		
		$controller_path = APPPATH.'modules/'.$path.$module.'/controllers/'.CONTROL_FOLDER.'/'.$controller.EXT;
		//echo $controller_path;exit; 
		if ( ! file_exists($controller_path))
		{
			show_error('Unable to locate the module you have specified: '.$path.$module.'/controllers/'.$controller.EXT);
		}
		
		if ( ! class_exists('JR_Module'))
		{
			require_once(APPPATH.'core/JR_Module'.EXT);
		}
		
		$class_name = $module."_".$controller;
		// echo $class_name;exit; 
		if (!isset($CI->$class_name))
		{
			// 装载 Module 控制器文件
			require_once($controller_path);
			$CI->$class_name = new $class_name(); 
		}
		
		$module_load = $CI->$class_name->load; 
		
		if(1==1)
		{
			//echo $controller." ".$method;exit; 
			ob_start();
			
			log_message('debug', 'Module call: '.$class_name.'->'.$method);
			// echo  'Module call: '.$class_name.'->'.$method;exit; 
			
			// Call the requested method.
			// Any URI segments present (besides the class/function) will be passed to the method for convenience
			$output = call_user_func_array(array($CI->$class_name, $method), $module_load->_ci_object_to_array($vars));
			
			if ($return === TRUE)
			{
				$buffer = ob_get_contents();
				@ob_end_clean();
			
				$result = ($output) ? $output : $buffer;
			
				return $result;
			}
			else
			{
				if (ob_get_level() > $this->_ci_ob_level + 1)
				{
					ob_end_flush();
				}
				else
				{
					$buffer = ob_get_contents();
					$result = ($output) ? $output : $buffer;
					$CI->output->append_output($result);
					@ob_end_clean();
				}
			}
		}
	}
	
	function pop_error($error_name)
	{
		return $this->session->flashdata($error_name); 
	}
	
	function Request()
	{
		$ci = & get_instance() ;
		return $ci->Request() ; 
	}
	
	function view($view, $vars = array(), $return = FALSE)
	{
		$_view = $view ;  
		if($this->work_space == 'controller')
		{ 
			$ci = &get_instance();
			$_view = $ci->template . "/" . $view;
			// echo APPPATH."views\\".$view.".php";exit;
			if(!file_exists(APPPATH."views/".$_view.EXT))
			{
				$_view =  "default/" . $view;
			}
		}
		//echo $view;
		//exit;  
		return parent::view($_view,$vars,$return);        
	} 
	
	function master_page($master_page)
	{
		$this->view($master_page);
	}
	
	function block($block_name)
	{
        // $func = $this->abc;
        // $func();
        // return;
		$block_name = "block_".$block_name;
		/*
		if(function_exists($block_name))
		{
			$block_name($this,$this->_ci_cached_vars);
		}
		*/
		
		if(class_exists($block_name))
		{
			$ob = new $block_name;
			/*
			// $_ci_CI =& get_instance();
			$_ci_CI = $this;
			foreach (get_object_vars($_ci_CI) as $_ci_key => $_ci_var)
			{
				if (!isset($ob->$_ci_key))
				{
					$ob->$_ci_key =& $_ci_CI->$_ci_key;
				}
			}
			*/   
			$ob->exe($this->_ci_cached_vars);   
		}
		
	}
	
	protected function _ci_load($_ci_data)
	{
        // parent::_ci_load($_ci_data);return;
        // print_r($_ci_data);exit;
        $code_cache_file = str_replace("/","_",$_ci_data['_ci_view']);
		// Set the default data variables
		foreach (array('_ci_view', '_ci_vars', '_ci_path', '_ci_return') as $_ci_val)
		{
			$$_ci_val = ( ! isset($_ci_data[$_ci_val])) ? FALSE : $_ci_data[$_ci_val];
		}
		
		$file_exists = FALSE;

		// Set the path to the requested file
		if ($_ci_path != '')
		{
			$_ci_x = explode('/', $_ci_path);
			$_ci_file = end($_ci_x);
		}
		else
		{
			$_ci_ext = pathinfo($_ci_view, PATHINFO_EXTENSION);
			$_ci_file = ($_ci_ext == '') ? $_ci_view.'.php' : $_ci_view;

			foreach ($this->_ci_view_paths as $view_file => $cascade)
			{
				if (file_exists($view_file.$_ci_file))
				{
					$_ci_path = $view_file.$_ci_file;
					$file_exists = TRUE;
					break;
				}
				
				if ( ! $cascade)
				{
					break;
				}				
			}
		}

        $is_has_error = false;
		if ( ! $file_exists && ! file_exists($_ci_path))
		{
			show_error('Unable to load the requested file: '.$_ci_file);
		}


        $_ci_CI =& get_instance();
        foreach (get_object_vars($_ci_CI) as $_ci_key => $_ci_var)
        {
            if ( ! isset($this->$_ci_key))
            {
                $this->$_ci_key =& $_ci_CI->$_ci_key;
            }
        }

        /*
         * Extract and cache variables
         *
         * You can either set variables using the dedicated $this->load_vars()
         * function or via the second parameter of this function. We'll merge
         * the two types and cache them so that views that are embedded within
         * other views can have access to these variables.
         */
        if (is_array($_ci_vars))
        {
            $this->_ci_cached_vars = array_merge($this->_ci_cached_vars, $_ci_vars);
        }
        extract($this->_ci_cached_vars);

        /*
         * Buffer the output
         *
         * We buffer the output for two reasons:
         * 1. Speed. You get a significant speed boost.
         * 2. So that the final rendered template can be
         * post-processed by the output class.  Why do we
         * need post processing?  For one thing, in order to
         * show the elapsed page load time.  Unless we
         * can intercept the content right before it's sent to
         * the browser and then stop the timer it won't be accurate.
         */
        ob_start();


        $code_file = FCPATH.$_ci_path;
        // echo $code_file;exit;
        // $code_cache_file = end(explode("/",$_ci_path));
        $code_cache_file = FCPATH."application/code_cache/$code_cache_file";
        //  echo $code_cache_file;exit;
        if(file_exists($code_cache_file) && (filectime($code_cache_file)>filectime($code_file)))
        {
            // exit("aa");
            $_jr_content = file_get_contents($code_cache_file);
        }
        else
        {


            // If the PHP installation does not support short tags we'll
            // do a little string replacement, changing the short tags
            // to standard PHP echo statements.
            $_jr_content = file_get_contents($_ci_path);

            //  $aa11 = microtime();
            $_jr_content =
            preg_replace(
                array(
                    '/{\s*block\s*(\S*)\s*}/i',
                    '/{\s*use\s+master_page\(\s*\'(\S*)\s*\'\)\s*}/i',
                    '/{\s*load\s+(\S*)\(\s*\'(\S*)\s*\'\)\s*}/i',
                    '/{\s*cache\s*?(\S+?)\s*?\(\s*?\[\s*(\S+?)\s*?,\s*?(\S+?)\s*?\]\s*?,\s*?(\d+?)\s*?\)\s*?}/i',
                    '/{\s*end\s+cache\s+(\S+)\s*}/i',
                    '/{#\s*(.*)\s*#}/i'
                ),
                array(
                    '<?php class block_$1 extends jr_block_loader {function exe($a){ extract($a); ?>',
                    '<?php $this->load->master_page("$1"); ?>',
                    '<?php $this->load->$1("$2");?>',
                    '<?php $ci = & get_instance();$ci->load->driver(\'cache\', array(\'adapter\' => \'$2\', \'backup\' => \'$3\'));if ( ! $$1_foo = $ci->cache->get(\'$1\')):$$1_t=$4;ob_start();?>',
                    '<?php $$1_foo = ob_get_contents();@ob_end_clean();$ci->cache->save(\'$1\', $$1_foo, $$1_t);endif;echo $$1_foo;?>',
                    '<?php $1?>'
                ),
                $_jr_content
            );

            $_jr_content =
                str_replace(
                    '{end}',
                    '<?php }}?>',
                    $_jr_content
                );
            /*
            $_jr_content =
                str_replace(
                    '\{\#',
                    '{#',
                    $_jr_content
                );
            */

            $_jr_content =
            preg_replace(
                array(
                    '/{\s*([a-zA-Z0-9>_-]+)\s*}/i',
                    '/{\$\s*([a-zA-Z0-9>_-]+)\s*}/i',
                ),
                array(
                    '<?php echo isset(\$$1)?\$$1:"{$1}";?>',
                    '<?php echo empty(\$$1)?\$$1:"{\$$1}";?>',
                ),
                $_jr_content
            );

            //  echo microtime() -  $aa11;
            if ((bool) @ini_get('short_open_tag') === FALSE AND config_item('rewrite_short_tags') == TRUE)
            {
                try
                {

                    $_jr_content = '?>'.str_replace('<?=', '<?php echo ', $_jr_content);
                    // echo eval();
                }
                catch(Exception $e)
                {
                    if(strpos($e->getMessage(), 'Cannot redeclare class')>0)
                    {
                        echo "Fatal error:Cannot have the same block define  不能有同名块";
                    }
                    $is_has_error = true;
                }
            }
            else
            {
                try
                {
                    $_jr_content = '?>'.
                        preg_replace(
                            "/;*\s*\?>/", "; ?>",
                            $_jr_content
                        );
                    // echo eval();

                    // print_r(error_get_last());
                }
                catch(Exception $e)
                {
                    if(strpos($e->getMessage(), 'Cannot redeclare class')>0)
                    {
                        echo "Fatal error:Cannot have the same block define  不能有同名块";
                    }
                    $is_has_error = true;
                }
                //include($_ci_path); // include() vs include_once() allows for multiple views with the same name
            }
            if(!$is_has_error){

                try
                {
                    // 缓存文件
                    $f = fopen($code_cache_file,"w");
                    fwrite($f,$_jr_content);
                    fclose($f);
                }catch(Exception $e)
                {
                    echo $e->getMessage();
                    $is_has_error = true;
                }
            }
        }

        if(!$is_has_error){

            echo eval($_jr_content);
        }

		log_message('debug', 'File loaded: '.$_ci_path);

		// Return the file data if requested
		if ($_ci_return === TRUE)
		{
			// echo "ddd";
			// exit;
			$buffer = ob_get_contents();
			@ob_end_clean();
			return $buffer;
		}

		//echo "abc";
		//exit;

		/*
		 * Flush the buffer... or buff the flusher?
		 *
		 * In order to permit views to be nested within
		 * other views, we need to flush the content back out whenever
		 * we are beyond the first level of output buffering so that
		 * it can be seen and included properly by the first included
		 * template and any subsequent ones. Oy!
		 *
		 */
		if (ob_get_level() > $this->_ci_ob_level + 1)
		{
			ob_end_flush();
		}
		else
		{
			$_ci_CI->output->append_output(ob_get_contents());
			@ob_end_clean();
		}
	}
} 

class JR_Block_Loader extends JR_Loader
{
	function __get($property_name)
	{
		if(!isset($this->$property_name))
		{
			$ci = & get_instance();
			$this->$property_name = $ci->$property_name;
		}
		return  $this->$property_name ; 
	}
}
